#ifndef __M_SINK_H__
#define __M_SINK_H__
#include "util.hpp"
#include "message.hpp"
#include "formatter.hpp"
#include <memory>
#include <mutex>


namespace dhylog
{
    class LogSink
    {
        public:
        using ptr = std::shared_ptr<LogSink>;
        LogSink() {}
        virtual void log(const char *data, size_t len) = 0;
    };
    class StdoutSink : public LogSink 
    {
        public:
        using ptr = std::shared_ptr<StdoutSink>;
        void log(const char *data, size_t len)override
        {
            std::cout.write(data,len);
            std::cout<<std::endl;
        }
    };
    class FileSink : public LogSink 
    {
        public:
        using ptr = std::shared_ptr<FileSink>;
        FileSink(const std::string &filename):_Filename(filename) 
        {
            util::File::create_directory(util::File::path(filename));
            _ofs.open(filename, std::ios::binary | std::ios::app);
            assert(_ofs.is_open());
        }
        void log(const char *data, size_t len)override
        {
            _ofs.write(data,len);
            if(_ofs.good()==false)
            {
                std::cout<<"日志文件输出失败"<<std::endl;
            }
        }
        private:
        std::string _Filename;
        std::ofstream _ofs;
    };
    class RollSink : public LogSink
    {
        public:
        using ptr = std::shared_ptr<RollSink>;
        RollSink(std::string basename,size_t max_fsize):_basename(basename),_max_fsize(max_fsize),_cur_fsize(0)
        {
            util::File::create_directory(util::File::path(basename));    
        }
         void log(const char *data, size_t len)override
        {
            initLogFile();
            _ofs.write(data,len);
            _ofs<<'\n';
            if (_ofs.good() == false) 
            {
                std::cout << "日志输出文件失败！\n";
            }
            _cur_fsize += len;
        }
        private:
        void initLogFile() 
        {
            if(_ofs.is_open()==false||_cur_fsize>=_max_fsize)
            {
                 _ofs.close();
                std::string name = createFilename();
                 _ofs.open(name, std::ios::binary | std::ios::app);
                 assert(_ofs.is_open());
                 _cur_fsize = 0;
                return;
            }
            return;
        }
        std::string createFilename()
        {
            time_t t=util::date::now();
            struct tm lt;
            localtime_r(&t, &lt);
            std::stringstream ss;
            ss << _basename;
            ss << lt.tm_year + 1900;
            ss << "-";
            ss << lt.tm_mon + 1;
            ss << "-";
            ss << lt.tm_mday;
            ss << "-";
            ss << lt.tm_hour;
            ss << "-";
            ss << lt.tm_min;
            ss << "-";
            ss << lt.tm_sec;
            ss << ".log";
            return ss.str();
        }
        std::string _basename;
        std::ofstream _ofs;
        size_t _max_fsize;
        size_t _cur_fsize;
    };

    class SinkFactory 
    {
    public:
        template<typename SinkType, typename ...Args>
        static LogSink::ptr create(Args &&...args) {
            return std::make_shared<SinkType>(std::forward<Args>(args)...);
        }
    };
}
#endif